import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.imageio.*;
import javax.swing.*;


public class BoardView extends JPanel implements ActionListener, MouseListener {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -6126395951370691647L;

	private Timer timer;
	
	private GameSettings gameSettings;
	private Board board;
	private int width;
	private int height;
	private int selectedX = -1;
	private int selectedY = -1;
	
	private Image jewelImage;	
	
    public BoardView(GameSettings gs, Board b) {
    	this.gameSettings = gs;
    	this.board = b;
    	
    	this.width = gs.getJewelSize() * this.gameSettings.getCols();
    	this.height = gs.getJewelSize() * this.gameSettings.getRows();
    	
        this.setBackground(Color.BLACK);
        this.setDoubleBuffered(true);
        
        this.createImage();

        timer = new Timer(25, this);
        timer.start();
    }
    
    private final void createImage() {
    	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    	InputStream input = classLoader.getResourceAsStream("jewels" + this.gameSettings.getJewelSize() + ".png");
    	
    	//InputStream input = classLoader.getResourceAsStream("jewels80.png");
    	
    	/*
    	InputStream test = classLoader.getResourceAsStream("test.txt");
    	try {
			System.out.println(convertStreamToString(test));
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		*/

    	try {
    		this.jewelImage = ImageIO.read(input);
    	} catch (IOException e) {
    	}
    }
        
    public final int getWidth() {
    	return this.width;
    }
    
    public final int getHeight() {
    	return this.height;
    }

    public void paint(Graphics g) {
        super.paint(g);

        //g.translate(0,25);//move origin down to compromise for the title bar

        this.redraw(g, this.board.getBoard());

     	Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }
    
	@Override
	public void actionPerformed(ActionEvent e) {
        this.repaint();
	}
	
	private final int getJewelSize() {
		return this.gameSettings.getJewelSize();
	}
	
	private void drawJewel(Graphics g1, int type, int x, int y) {
		final Graphics2D g = (Graphics2D)g1.create();
	    try {	    
			int xOffset = this.getJewelSize() * type;
			
			g.translate(x * this.getJewelSize(), y * this.getJewelSize());
			
			g.drawImage(
				this.jewelImage, 
				0, 
				0, 
				this.getJewelSize(),
				this.getJewelSize(),
				xOffset,
				0,
				xOffset + this.getJewelSize(),
				this.getJewelSize(),
				null);
	    } finally {
	         g.dispose();
	    }
	}
	
	private void redraw(Graphics g1, int[][] newJewels) {
		final Graphics2D g = (Graphics2D)g1.create();
	    try {
			g.setColor(this.getBackground());
			g.fillRect(0, 0, this.width, this.height);
			
			for (int x = 0; x < this.getCols(); x++) {
				for (int y = 0; y < this.getRows(); y++) {
					drawJewel(g, newJewels[x][y], x, y);
				}
			}		
	    } finally {
	         g.dispose();
	    }
	}

	private int getRows() {
		return this.gameSettings.getRows();
	}

	private int getCols() {
		return this.gameSettings.getCols();
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// figure out which jewel
		int dx, dy, dist;
		int xOffset = e.getX() / this.getJewelSize();
		int yOffset = e.getY() / this.getJewelSize();

		if (!this.isCursorSet()) {
			this.selectedX = xOffset;
			this.selectedY = yOffset;
			return;
		}
		
		dx = Math.abs(xOffset - this.selectedX);
		dy = Math.abs(yOffset - this.selectedY);
		dist = dx + dy;
		
		if (dist == 0) {
			// clicked on same jewel so de-select
			this.setCursor(xOffset, yOffset, false);
		} else if (dist == 1) {
			this.board.swap(this.selectedX, this.selectedY, xOffset, yOffset);
			this.setCursor(xOffset, yOffset, false);
		} else {
			// select a different jewel
			this.setCursor(xOffset, yOffset, true);
		}
	}
	
	private void setCursor(int x, int y, boolean select) {
		if (select) {
			this.selectedX = x;
			this.selectedY = y;
		} else {
			this.selectedX = -1;
			this.selectedY = -1;
		}
	}
	
	private boolean isSelectionSet() {
		// check for current selection by looking for non-negative selectedX
		return this.selectedX >= 0;
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
	}
}
